#ifndef RNTSTRATEGY_H
#define RNTSTRATEGY_H


#if defined (_WIN32)
	#pragma once
#endif

#include <LDF/VisComponentStrategy.h>
#include "../../ToolkitLayer.h"
#include <LDF/VisComponent.h>
#include <LDF/LargeDisplayManager.h>


/**
 * This class implement the RNT (Rotate 'N Translate) behavior strategy. It is
 * based on the implementation given in the VisComponent class in the original
 * version of the framework done by A. Miede and T. Isenberg in the
 * Interactions Lab at the University of Calgary, Canada, and on the original
 * RNT paper: "Fluid Integration of Rotation and Translation" by R. Kruger et
 * al.
 *
 * @author Fabricio Anastacio - fabriciocfa@yahoo.com
 * @since July 31, 2007
 */
class TOOLKITLAYER_API RNTStrategy : public VisComponentStrategy
{
	// Attributes
protected:
	/** The color of the RNT decoration (e. g., the inner circle). */
	float color[4];
	/** Determines when the component is being pressed. */
	bool pressed;
	/** The previous x-coordinate of the cursor position. */
	float previousX;
	/** The previous y-coordinate of the cursor position. */
	float previousY;
	/** The percentage of the smallest dimension that is used to calculate the
	 * radius of the translation-only area inside the component. */
	float translationRadiusFactor;
	/** The line width of the RNT decoration (e. g., the inner circle) */
	float decorationWidth;
	/** Defines if the RNT decoration (e. g., the inner circle) should be drawn. */
	bool drawDecoration;

	/** Button buffer type identifier. */
	unsigned int buttonBufferType;

	// BUTTON BUFFER VALUES
	/** No button value. */
	unsigned char noButtonValue;
	/** Movable area button value. */
	unsigned char movableAreaButtonValue;
	/** RNT area button value. */
	unsigned char rntAreaButtonValue;

	/** The number of segments the decoration circle is divided. */
	unsigned int nSegments;

	/** The display list identifier. */
	unsigned int dlCircle;
	/** The width value currently used by the display list. */
	unsigned int dlWidth;
	/** The height value currently used by the display list. */
	unsigned int dlHeight;
	/** The scaleX value currently used by the display list. */
	float dlScaleX;
	/** The scaleY value currently used by the display list. */
	float dlScaleY;

	// DRAWING TIMEOUT
	/** The number of frames that the decorative circle should be displayed
	 * after the component is released. */
	int frameTimeout;
	/** The number of frames the circle fading out should last. */
	int frameDuration;
	/** The counter for the number of frames since the component release. */
	int frameCount;
	/** The number of seconds that the decorative circle should be displayed
	 * after the component is released. */
	float secsTimeout;
	/** The number of seconds the circle fading out should last. */
	float secsDuration;


	// Methods
public:
	RNTStrategy(void);
	~RNTStrategy(void);

	// ACCESSOR METHODS
	/**
	 * Returns the color used to draw the RNT decoration as an array of 4
	 * floats.
	 *
	 * @return the color used to draw the RNT decoration.
	 */
	inline float* getColor() { return color; };
	/**
	 * Sets the color to be used for drawing the RNT decoration as an array of
	 * 4 floats.
	 *
	 * @param c the color to be used for drawing the RNT decoration.
	 */
	inline void setColor(float* c) { color[0] = c[0]; color[1] = c[1]; color[2] = c[2]; color[3] = c[3]; };
	/**
	 * Returns the value of the percentage of the smallest dimension that is
	 * used to calculate the radius of the translation-only area inside the
	 * component.
	 *
	 * @return the value of the percentage of the smallest dimension that is
	 * used to calculate the radius of the translation-only area.
	 */
	inline float getTranslationRadiusFactor() { return translationRadiusFactor; };
	/**
	 * Sets the value of the percentage of the smallest dimension that is
	 * used to calculate the radius of the translation-only area inside the
	 * component.
	 *
	 * @param f the value to be used as the percentage of the smallest
	 * dimension that is used to calculate the radius of the translation-only
	 * area.
	 */
	inline void setTranslationRadiusFactor(float f) { translationRadiusFactor = f; };
	/**
	 * Returns the value of the line width used for decoration drawings.
	 *
	 * @return the value of the line width used for decoration drawings.
	 */
	inline float getDecorationWidth() { return decorationWidth; };
	/**
	 * Sets the value of the line width used for decoration drawings.
	 *
	 * @param w the value to be used as the line width used for decoration.
	 */
	inline void setDecorationWidth(float w) { decorationWidth = w; };
	/**
	 * Returns true if the RNT decoration should be drawn.
	 *
	 * @return true if the RNT decoration should be drawn, false otherwise.
	 */
	inline bool getDrawDecoration() { return drawDecoration; };
	/**
	 * Sets if the RNT decoration should be drawn.
	 *
	 * @param value true if the RNT decoration should be drawn, false otherwise.
	 */
	inline void setDrawDecoration(bool value) { drawDecoration = value; };
	/**
	 * Returns the number of segments in which the decoration circle is divided.
	 *
	 * @return the number of segments in which the decoration circle is divided.
	 */
	unsigned int getNumberSegements() { return nSegments; };
	/**
	 * Sets the number of segments in which the decoration circle is divided.
	 *
	 * @param nSegs the number of segments in which the decoration circle is divided.
	 */
	void setNumberSegments(unsigned int nSegs) { nSegments = nSegs; };
	/**
	 * Returns the number of seconds that the decorative circle should be
	 * displayed after the component is released.
	 *
	 * @return the number of seconds that the RNT circle should be displayed.
	 */
	float getSecsTimeout() { return secsTimeout; };
	/**
	 * Sets the number of seconds that the decorative circle should be
	 * displayed after the component is released.
	 *
	 * @param secs the number of seconds that the RNT circle should be
	 * displayed.
	 */
	void setSecsTimeout(float secs) { secsTimeout = secs; };
	/**
	 * Returns the number of seconds that the fading out of the decorative
	 * circle should last.
	 *
	 * @return the number of seconds that the RNT circle fade out should last.
	 */
	float getSecsDuration() { return secsDuration; };
	/**
	 * Sets the number of seconds that the fading out of the decorative
	 * circle should last.
	 *
	 * @param secs the number of seconds that the RNT circle fade out should
	 * last.
	 */
	void setSecsDuration(float secs) { secsDuration = secs; };


protected:
	/**
	 * Creates the display list to draw the decoration circle.
	 */
	virtual void createDisplayList();

	/**
	 * Initializes the properties (i. e., i-buffers) of the associated
	 * component.
	 */
	void initProperties() {};
	/**
	 * Defines the drawing strategy for the associated component.
	 *
	 * @param enablePicking if true, draw for selection mode (adding the
	 * component id).
	 */
	void draw(const std::vector<unsigned long>& selectedIds);
	/**
	 * Defines the drawing strategy for the associated component that should be
	 * used for picking.
	 */
	void drawForPicking() {};
	/**
	 * Handles the given event.
	 *
	 * @param evt the event to be handled.
	 */
	void onEvent(LargeDisplayEvent* evt);
	/**
	 * Defines the strategy to be used when the associated component is
	 * resized.
	 *
	 * @param width the new width of the component.
	 * @param height the new height of the component.
	 */
	void resize(unsigned int width, unsigned int height) {};
	/**
	 * Defines the strategy to be used when the associated component is
	 * "dropped" inside another component (likely, a container). It is called
	 * when the component is processed from the manager's update list. It
	 * usually defines some "decorative" behavior such as triggering
	 * animations, since the composition structure is already managed by the
	 * LargeDisplayManager class. Returns true if this call resulted in
	 * adding the component to a container with animation.
	 *
	 * @param parentChanged true if the component's parent changed with the
	 * dropping.
	 * @return true if this call resulted in adding or keeping the component to
	 * a container with animation, false otherwise.
	 */
	bool drop(bool parentChanged) { return false; };
	/**
	 * Reads the passive buffer(s) specified by the parameter 'type' and makes
	 * the proper updates in the state of the associated component.
	 *
	 * @param type the type of buffer that should be read from the container.
	 */
	inline void readPassiveBuffers(const std::vector<unsigned int>& types) {};
	/**
	 * Reads all the passive buffers for a component strategy. This method is
	 * called before drawing the component in order to update its
	 * state/properties.
	 */
	inline void readAllPassiveBuffers() {};
	/**
	 * Reads only the passive buffers for a component strategy that are
	 * necessary for picking processing. This method is called before drawing
	 * the component for picking in order to update its state/properties.
	 */
	inline void readAllPickingPassiveBuffers() {};


protected:
	/**
	 * Applies the RNT trasformation to the associated component. Returns true
	 * if the displacement placed the component out of the display dimensions.
	 *
	 * @return true if the displacement placed the component out of the display
	 * dimensions.
	 */
	bool applyRNT(float x, float y);
	/**
	 * Returns true if the given x- and y-coordinates are inside the
	 * translation only circle of this component.
	 *
	 * @param x the x-coordinate of the point to be checked.
	 * @param y the y-coordinate of the point to be checked.
	 * @return true if the given x- and y-coordinates are inside the
	 * translation only circle of this component, false otherwise.
	 */
	bool isInsideTranslationArea(float x, float y);
	/**
	 * Returns the value of the current active button buffer of the associated
	 * component at the given global coordinates. If there is no button buffer
	 * currently active for the associated component or the coordinates are not
	 * inside the buffer, a constant value for NO_BUTTON is returned.
	 *
	 * @param x the x global coordinate to be checked.
	 * @param y the y global coordinate to be checked.
	 * @return the value retrieved from the button buffer or
	 * a constant value for NO_BUTTON in case of failure.
	 */
	unsigned char getButtonValue(unsigned int x, unsigned int y);

};

#endif // RNTSTRATEGY_H
